module SynAn where

import qualified Data.Map as M
import qualified Data.Set as S
import Data.List
import Data.Maybe

type State = String 
type Lexeme = (String, String)
type Transitions = M.Map (State, String, StackSymbol) 
                         (State, StackSymbol, [Action])

type StackSymbol = String
type Stack = [StackSymbol]
type Code = ([String], Integer)
type Buffer = ([String], [String], Code)

type ActionSet = (String, Stack, Buffer)
type Action = ActionSet -> ActionSet 

data FSM = FSM
  {
    start_state :: State
  , eos :: String
  , empty_el :: String
  , empty_stack :: String
  , halt :: State
  , delta :: Transitions
  }

-------------------------------------------------------------
(?) cond (a, b) = if cond then a else b

execFSM :: FSM -> [Lexeme] -> Code 
execFSM (FSM s_state eos empty_e empty_s halt delta) str =  
  next str s_state [] ([], [], ([], 0)) 1

  where
    next :: [Lexeme] -> State -> Stack -> Buffer -> Integer -> Code
    next str cur_state stack buf num = 
      --if num == 3
      --then error ((show symbol') ++ (show symbol'') ++ (show symbol))
      --else 
      case n_state of
        --"" -> error ("Error in lex " ++ (show num) ++ (show symbol') ++ (show symbol'') ++ (head stack) ++ "!\n")
        "" -> error ("Error in lex " ++ (show num) ++ "!\n")
        otherwise -> 
          (n_state == halt) ? (n_code, 
                               next n_str n_state n_stack n_buf (num+1))

      where
        end = null str
        out = cur_state == halt 
        (x:xs) = end ? ([], str)
        n_str = end ? ([], xs)
        s_head = null stack ? (empty_s, head stack)
        
        symbol' = (cur_state, end ? (eos, fst x), empty_e)
        symbol'' = (cur_state, end ? (eos, fst x), s_head)
        symbol = (symbol' `M.member` delta) ? (symbol', symbol'')
        (n_state, s_head', actions) = 
          M.findWithDefault ("", "", []) symbol delta
        --n_s_head = (s_head' == empty_e) ? ("", s_head')

        compos = foldl (.) id (reverse actions) 
        (_, n_stack, n_buf) = compos (snd x, stack, buf)
        (_, _, n_code) = n_buf



